-
Notifications
You must be signed in to change notification settings - Fork 63
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Databases tree view #245
Databases tree view #245
Conversation
…h databaseQuerier interface
pkg/client/client.go
Outdated
var ( | ||
resultSet = [][]string{} | ||
db *sqlx.DB | ||
) | ||
|
||
if c.activeDatabase != "" { | ||
switch c.driver { | ||
case drivers.Postgres, drivers.PostgreSQL, drivers.MySQL: | ||
db = c.dbs[c.activeDatabase] | ||
} | ||
} else { | ||
db = c.db | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about this?
var ( | |
resultSet = [][]string{} | |
db *sqlx.DB | |
) | |
if c.activeDatabase != "" { | |
switch c.driver { | |
case drivers.Postgres, drivers.PostgreSQL, drivers.MySQL: | |
db = c.dbs[c.activeDatabase] | |
} | |
} else { | |
db = c.db | |
} | |
var ( | |
resultSet = [][]string{} | |
) | |
db = c.db | |
if c.activeDatabase != "" { | |
switch c.driver { | |
case drivers.Postgres, drivers.PostgreSQL, drivers.MySQL: | |
db = c.dbs[c.activeDatabase] | |
} | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is so nice and elegant. Good catch!
pkg/client/client.go
Outdated
if c.activeDatabase != "" { | ||
switch c.driver { | ||
case drivers.Postgres, drivers.PostgreSQL, drivers.MySQL: | ||
db = c.dbs[c.activeDatabase] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about this?
db = c.dbs[c.activeDatabase] | |
db, ok = c.dbs[c.activeDatabase] | |
if !ok { | |
return nil, nil, return nil, fmt.Errorf("connection with %s database not found", c.activeDatabase) | |
} |
I'm afraid about possible panic, when calling db.Query
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, good catch there!
I'll add this.
Thanks!
func (c *Client) PreviousPage() (*Table, int, error) { | ||
if err := c.paginationManager.PreviousPage(); err != nil { | ||
return nil, 0, err | ||
tables = append(tables, table) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Each row.Nect loop must be followed by checking rows.Err()
} | |
} | |
if err:= rows.Err(); err != nil { | |
return nil, err | |
} |
return c.db | ||
} | ||
databases = append(databases, database) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same issue about missing rows.Err check
pkg/client/client.go
Outdated
if driver == drivers.MySQL { | ||
newConnString = strings.Replace(connString, "/", fmt.Sprintf("/%s", database), 1) | ||
} else { | ||
u, err := url.Parse(connString) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
u.Path = "/" + database | ||
newConnString = u.String() | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would use a switch and return an error when it's none of the supported database types
I'm a bit worried by the fact you will apply the postgres way to any future database type that might be added
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with using a switch here, but the driver validation is done somewhere. If the execution reaches this point, the driver is actually valid. Regarding applying the postgres way, yeah a switch statement might help supporting a new use case.
pkg/client/client.go
Outdated
db, err := sqlx.Open(driver, newConnString) | ||
if err != nil { | ||
|
||
panic(err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why a panic?
panic(err) | |
return nil, err |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left it there by accident. I'll remove it,
Thanks!
@@ -39,7 +39,15 @@ func TestMain(m *testing.M) { | |||
func generateURL(driver string) string { | |||
switch driver { | |||
case drivers.Postgres: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why postgresql const is not present here? Isn't it tested?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because the that constant is the one used at the time to test on CI. I can only use one at a time there.
pkg/client/client_test.go
Outdated
assert.Greater(t, len(r), 0) | ||
assert.Greater(t, len(co), 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
assert.Greater(t, len(r), 0) | |
assert.Greater(t, len(co), 0) | |
assert.NotEmpty(t, r) | |
assert.NotEmpty(t, co) |
pkg/client/client_test.go
Outdated
assert.Greater(t, len(r), 0) | ||
assert.Greater(t, len(co), 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same you could use NotEmpty
pkg/tui/tui.go
Outdated
// if i == 0 { | ||
// t.aw.content.SetCell(i+1, j, &tview.TableCell{Text: sc, Color: tcell.ColorRed}) | ||
// } else { | ||
// } | ||
t.aw.content.SetCellSimple(i+1, j, sc) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why leaving commented out code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch!
I was testing out new colors.
Hey @ccoVeille! What a good code review there! I already addressed all your comments. Let me know if I missed something. Thanks so much! P.S. Can I include you as a reviewer from this point on? |
Thanks, you are welcome
Sure |
Maybe you could add a co-authored-by tag You can find my email here So, just add this to the commit message of the changes you made with my review
|
default: | ||
u, err := url.Parse(connString) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
u.Path = "/" + database | ||
newConnString = u.String() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would be safer (I might have forgotten some)
default: | |
u, err := url.Parse(connString) | |
if err != nil { | |
return nil, err | |
} | |
u.Path = "/" + database | |
newConnString = u.String() | |
case drivers.PostgreSQL, drivers.Postgres: | |
u, err := url.Parse(connString) | |
if err != nil { | |
return nil, err | |
} | |
u.Path = "/" + database | |
newConnString = u.String() | |
default: | |
return nil, fmt.Errorf("unsupported driver %s", driver) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I disagree with this, since the driver validation is done somewhere else and the MySQL URL parsing is the corner case here The default behavior is parsing the DSN
with url.Parse
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah OK then. I misunderstood
assert.Greater(t, len(m.Indexes.Rows), 0) | ||
assert.Greater(t, len(m.Indexes.Columns), 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use NotEmpty
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
testifylint linter could help you a lot with such "issue"
It would also detect when you should use require.NoError
https://github.com/Antonboom/testifylint
It can be added easily to golangci-lint, bit you don't have golangci-lint yet,
maybe
I can help you here if you want
c, err := New(opts) | ||
assert.NoError(t, err) | ||
|
||
tables, err := c.ShowTables() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here you should (must) use
c, err := New(opts) | |
assert.NoError(t, err) | |
tables, err := c.ShowTables() | |
c, err := New(opts) | |
require.NoError(t, err) | |
tables, err := c.ShowTables() |
require is another package available in testify
The reason is that if an error is returned by New, c will be nil, so c.ShowTables will panic
Test should never panic
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, let's focus on the scope of the PR. We can address the test suite in another PR and issue. This test suite is not new, it's been 3 years since I set it up. I'm willing to improve it but later.
@@ -212,23 +221,20 @@ func TestTableStructure(t *testing.T) { | |||
Pass: password, | |||
Host: host, | |||
Port: port, | |||
DBName: name, | |||
Schema: schema, | |||
SSL: "disable", | |||
Limit: 100, | |||
} | |||
|
|||
c, _ := New(opts) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You shouldn't ignore the error here
@@ -247,17 +253,14 @@ func TestConstraints(t *testing.T) { | |||
|
|||
c, _ := New(opts) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same
t.Logf("constraints columns %v", co) | ||
t.Logf("constraints content %v", r) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These logs are not needed. If the test fail, you will get the info. If it doesn't fail, I don't see a need to see these lines when running a go test
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's create an issue to improve the test suite.
2f01c7e
to
e64fa29
Compare
Alright @ccoVeille, I just added the co-authored tag. Honor when honor is due. Can you go over the PR again, please? I 'd like to land this change tonight. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice work man
Add a view to see databases and their tables
Description
The vast majority of database client software, if not all, show a list of databases and their tables as a tree structure. This is convenient for users that want to see all the database the have access to.
When it comes to dblab, things used to be a bit different, because database parameter was always required, either as a cli flag value or as part of the DSN. This was this way for the longest time because one reason. First off,
dblab
was heavily inspired by pgweb. This was the client I used to use at work, but suddenly I got tasked to manage a couple of microservices tied to MySQL databases, and I needed a FOSS alternative for Linux that worked as well aspgweb
for my use case.pgweb
rquires a database to connect to and only display its tables as a list. Then I tried to mimic a pgweb like client in the terminal and that's how dblab started. But things have changed I my needs have evolved and sometimes I need to look at other databases as well.This MR basically removes the mandatory status of the database parameter and makes it optional. If the database is not provided, then, a tree structure is displayed showig databases and their tables.
Another important change has been made and it was removing the pagination. I have rarely found myself using it, because it's faster to make query to where I need to be.
Fixes #209
Fixes #232
Type of change
Please delete options that are not relevant.
How Has This Been Tested?
Tested it against pagila databse and the testing database of the project
Checklist: